using System.IO;
using System.Windows.Forms;
using System.Xml;

using GSNConf.Rules;
using GSN.Rules;
using GSN.Config;

namespace GSNConf
{
    class SettingsException : System.Exception
    {
        public SettingsException(string str)
            : base(str)
        {
        }
    }

    class GSNSettings
    {
        internal class GSNMailSettings
        {
            public string type = null;
            public string username = null;
            public string password = null;
            public string server = null;
            public int port = 110;
            public string labels = null;
        }

        private int interval = 15;
        /*private string icqUin = null;
        private string icqPassword = null;*/
        private bool log = true;
        private string phone = null;
        private bool passwordsEncrypted = false; // default value is false for backwards comptability.
        private bool autoVersionCheck = true;
        private string smsTemplate = "You've got mail from %From%. %Subject%: %Body%";

        private GSN.Senders.SMSSenderFactory.SmsProviders smsProviderType = GSN.Senders.SMSSenderFactory.SmsProviders.None;
        private GSN.Senders.ISMSSender smsSender = null;

        private GSNMailSettings mailSettings = new GSNMailSettings();

        private IRule[] rules = null;

        private static string GSNConfigFile = Path.GetDirectoryName(Application.ExecutablePath) + "\\" + "GSN.xml";


        public void load()
        {
            if (!File.Exists(GSNConfigFile))
                return;

            XmlDocument doc = new XmlDocument();
            try
            {
                doc.Load(GSNConfigFile);
            }
            catch (System.Exception)
            {
                doc = null;
                return;
            }

            XmlNode node = null;

            // read first, before passwords so I'll know whether to decode them or not.
            node = doc.SelectSingleNode("GSN/Settings/PasswordsEncrypted");
            if (node != null)
            {
                passwordsEncrypted = bool.Parse(node.InnerText);
            }

            interval = int.Parse(doc.SelectSingleNode("GSN/Settings/Interval").InnerText);

            XmlPasswordNode pNode = null;

            // for previous versions
            node = doc.SelectSingleNode("GSN/Settings/ICQ/UIN");
            if (node != null)
            {
                // this is an old version, use icq as sms provider
                smsProviderType = GSN.Senders.SMSSenderFactory.SmsProviders.ICQ;
                pNode = new XmlPasswordNode(node, passwordsEncrypted);                

                //GSNConf.Senders.ICQSMSSenderConfigurator c = new GSNConf.Senders.ICQSMSSenderConfigurator();
                //c.setItemString(node.InnerText, "Username");                
                string uin = pNode.InnerText;
                node = doc.SelectSingleNode("GSN/Settings/ICQ/Password");
                string pass = "";
                if (node != null)
                {
                    pNode = new XmlPasswordNode(node, passwordsEncrypted);
                    pass = pNode.EncryptedInnerText;
                }
                smsSender = new GSN.Senders.ICQSMSSender(uin, pass);
            }
            // if not older version
            if (smsProviderType == GSN.Senders.SMSSenderFactory.SmsProviders.None)
            {
                node = doc.SelectSingleNode("GSN/Settings/SMS/Provider");
                if (node != null)
                    smsProviderType = (GSN.Senders.SMSSenderFactory.SmsProviders)int.Parse(node.InnerText);

                smsSender = null;

                switch (smsProviderType)
                {
                    case GSN.Senders.SMSSenderFactory.SmsProviders.ForeverSMS:
                        //smsSender = new GSN.Senders.ForeverSMSSender();
                        break;
                    case GSN.Senders.SMSSenderFactory.SmsProviders.ICQ:
                        smsSender = new GSN.Senders.ICQSMSSender();
                        break;
                    case GSN.Senders.SMSSenderFactory.SmsProviders.Skype:
                        smsSender = new GSN.Senders.SkypeSMSSender();
                        break;
                    case GSN.Senders.SMSSenderFactory.SmsProviders.Magtifun:
                        smsSender = new GSN.Senders.MagtifunSender();
                        break;
                }

                if (smsSender != null)
                {
                    node = doc.SelectSingleNode("GSN/Settings/SMS");
                    smsSender.load(new GSN.Config.XmlPasswordNode(node, passwordsEncrypted));
                }
            }

            node = doc.SelectSingleNode("GSN/Settings/Log");
            if (node == null)
                log = false;
            else
                log = ( node.InnerText == "on");

            phone = doc.SelectSingleNode("GSN/Settings/Phone").InnerText;

            mailSettings.type = doc.SelectSingleNode("GSN/Settings/Mail/Type").InnerText;
            mailSettings.username = doc.SelectSingleNode("GSN/Settings/Mail/Username").InnerText;

            pNode = new XmlPasswordNode(doc.SelectSingleNode("GSN/Settings/Mail/Password"), passwordsEncrypted);
            mailSettings.password = pNode.EncryptedInnerText;

            node = doc.SelectSingleNode("GSN/Settings/Mail/Labels");
            if (node != null)
            {
                mailSettings.labels = node.InnerText;
            }

            node = doc.SelectSingleNode("GSN/Settings/Mail/Server");
            if (node != null)
            {
                mailSettings.server = node.InnerText;
            }

            node = doc.SelectSingleNode("GSN/Settings/Mail/Port");
            if (node != null)
                mailSettings.port = int.Parse(node.InnerText);

            node = doc.SelectSingleNode("GSN/Settings/AutoVersionCheck");
            if (node != null)
                autoVersionCheck = bool.Parse(node.InnerText);

            node = doc.SelectSingleNode("GSN/Settings/SmsTemplate");
            if (node != null)
                smsTemplate = node.InnerText;

            rules = RulesConfigManager.loadRules(doc.SelectNodes("GSN/Settings/Rules/Rule"));

        }

        private Control findControl(string id, Form f)
        {
            Control[] c = f.Controls.Find(id, true);
            return c[0];

        }

        /// <summary>
        /// sets settings saved in object into the form
        /// </summary>
        /// <param name="f"></param>
        public void setSavedSettings(Form f)
        {
            ((NumericUpDown)findControl("numInterval", f)).Value = interval;
            /*((TextBox)findControl("txtIcqUin",f)).Text = icqUin;
            ((TextBox)findControl("txtIcqPassword", f)).Text = icqPassword;*/
            ((CheckBox)findControl("cbLogging", f)).Checked = log;
            ((TextBox)findControl("txtPhoneNumber", f)).Text = phone;
            ((ComboBox)findControl("boxMailType", f)).SelectedIndex = ((ComboBox)findControl("boxMailType", f)).FindString(mailSettings.type);
            ((TextBox)findControl("txtUsername", f)).Text = mailSettings.username;
            ((TextBox)findControl("txtPassword", f)).Text = mailSettings.password;
            ((TextBox)findControl("txtLabels", f)).Text = mailSettings.labels;
            ((TextBox)findControl("txtServer", f)).Text = mailSettings.server;
            ((TextBox)findControl("txtPort", f)).Text = mailSettings.port.ToString();
            ((CheckBox)findControl("cbPasswordsEncrypted", f)).Checked = passwordsEncrypted;
            ((CheckBox)findControl("cbAutoVersionCheck", f)).Checked = autoVersionCheck;
            ((TextBox)findControl("txtSmsTemplate", f)).Text = smsTemplate;

            // sms senders 
            ComboBox cbSmsProviders = (ComboBox)findControl("cbSmsProviders", f);
            //cbSmsProviders.SelectedIndex = (int)smsProviderType;
            if (smsSender != null)
            {
                for (int i = 0; i < cbSmsProviders.Items.Count; i++)
                {
                    if (cbSmsProviders.Items[i].GetType().ToString().CompareTo(smsSender.GetType().ToString()) == 0)
                    {
                        cbSmsProviders.Items[i] = smsSender;
                        cbSmsProviders.SelectedIndex = i;
                        break;
                    }
                }
            }

            /*if (smsProviderUsername != null && smsProviderPassword != null)
            {
                ((GSN.Config.IConfigurator)((ComboBox)findControl("cbSmsProviders", f)).SelectedItem).setItemString(smsProviderUsername, "Username");
                ((GSN.Config.IConfigurator)((ComboBox)findControl("cbSmsProviders", f)).SelectedItem).setItemString(smsProviderPassword, "Password");
            }*/

            // rules
            if (rules != null)
            {
                ListView listRules = (ListView)findControl("listRules", f);
                foreach (IRule rule in rules)
                {
                    ListViewItem item = new ListViewItem();
                    item.Text = rule.getName();
                    item.SubItems.Add(rule.getDescription());
                    item.Tag = rule;
                    listRules.Items.Add(item);
                }
            }
        }

        public void getFormSettings(Form f)
        {
            interval = int.Parse(((NumericUpDown)findControl("numInterval", f)).Value.ToString());
            /*icqUin = ((TextBox)findControl("txtIcqUin", f)).Text;
            icqPassword = ((TextBox)findControl("txtIcqPassword", f)).Text;*/
            log = ((CheckBox)findControl("cbLogging", f)).Checked;
            phone = ((TextBox)findControl("txtPhoneNumber", f)).Text;
            if (((ComboBox)findControl("boxMailType", f)).SelectedIndex >= 0)
            {
                mailSettings.type = ((ComboBox)findControl("boxMailType", f)).SelectedItem.ToString();
                mailSettings.username = ((TextBox)findControl("txtUsername", f)).Text;
                mailSettings.password = ((TextBox)findControl("txtPassword", f)).Text;
                mailSettings.labels = ((TextBox)findControl("txtLabels", f)).Text;
                mailSettings.server = ((TextBox)findControl("txtServer", f)).Text;
                mailSettings.port = int.Parse(((TextBox)findControl("txtPort", f)).Text);
            }
            passwordsEncrypted = ((CheckBox)findControl("cbPasswordsEncrypted", f)).Checked;
            autoVersionCheck = ((CheckBox)findControl("cbAutoVersionCheck", f)).Checked;
            smsTemplate = ((TextBox)findControl("txtSmsTemplate", f)).Text;

            // sms senders
            int smsProviderSelectedIndex = ((ComboBox)findControl("cbSmsProviders", f)).SelectedIndex;
            //smsProviderType = (GSN.Senders.SMSSenderFactory.SmsProviders)((ComboBox)findControl("cbSmsProviders", f)).SelectedIndex;
            if (smsProviderSelectedIndex >= 0)
            {
                smsSender = (GSN.Senders.ISMSSender)((ComboBox)findControl("cbSmsProviders", f)).SelectedItem;
                smsProviderType = GSN.Senders.SMSSenderFactory.getSenderType(smsSender);
                /*smsProviderUsername = ((GSN.Config.IConfigurator)((ComboBox)findControl("cbSmsProviders", f)).SelectedItem).getItemString("Username");
                smsProviderPassword = ((GSN.Config.IConfigurator)((ComboBox)findControl("cbSmsProviders", f)).SelectedItem).getItemString("Password");*/
            }
            else
            {
                smsSender = null;
                smsProviderType = GSN.Senders.SMSSenderFactory.SmsProviders.None;
            }

            // rules
            ListView listRules = (ListView)findControl("listRules", f);
            System.Collections.Generic.List<IRule> rl = new System.Collections.Generic.List<IRule>();
            foreach (ListViewItem item in listRules.Items)
            {
                rl.Add((IRule)item.Tag);
            }
            rules = rl.ToArray();
        }

        private void validate()
        {
            if (smsProviderType == GSN.Senders.SMSSenderFactory.SmsProviders.None)
                throw new SettingsException("Please Choose SMS Provider");

            /*@@@if (smsProviderUsername == null || smsProviderUsername.Length == 0)
                throw new SettingsException("SMS Provider Username is Empty!");

            if (smsProviderPassword == null || smsProviderPassword.Length == 0)
                throw new SettingsException("SMS Provider Password is Empty!");*/

            if (phone.Length == 0)
                throw new SettingsException("Phone Number is Empty!");

            if (mailSettings.type == null)
                throw new SettingsException("Mail Settings are Empty!");

            if (mailSettings.username.Length == 0)
                throw new SettingsException("Mail Username is Empty!");

            if (mailSettings.password.Length == 0)
                throw new SettingsException("Mail Password is Empty!");

            if (mailSettings.type.ToLower() == "pop3" || mailSettings.type.ToLower() == "imap")
            {
                if (mailSettings.server.Length == 0)
                    throw new SettingsException("Mail Server is Empty!");

                if (mailSettings.port <= 0)
                    throw new SettingsException("Illegal Mail Server Port!");
            }
        }

        public void save()
        {
            validate();

            XmlWriterSettings s = new XmlWriterSettings();
            s.Indent = true;
            
            XmlWriter w = XmlWriter.Create(GSNConfigFile, s);

            w.WriteStartElement("GSN");
            w.WriteStartElement("Settings");

            w.WriteComment("e-mail checking interval (minutes)");
            w.WriteElementString("Interval", interval.ToString());

            w.WriteStartElement("SMS");
            w.WriteElementString("Provider", ((int)smsProviderType).ToString());
            smsSender.save(new GSN.Config.XmlPasswordWriter(w, passwordsEncrypted));
            
            /*w.WriteElementString("Username", smsProviderUsername);
            if (passwordsEncrypted)
                w.WriteElementString("Password", GSN.CryptUtils.encrypt(smsProviderPassword));
            else
                w.WriteElementString("Password", smsProviderPassword);*/
            w.WriteEndElement();

            w.WriteElementString("Log", (log?"on":"off"));
            w.WriteComment("mobile phone number to be notified (including country code)");
            w.WriteElementString("Phone", phone);
            w.WriteElementString("PasswordsEncrypted", passwordsEncrypted.ToString());
            w.WriteElementString("AutoVersionCheck", autoVersionCheck.ToString());

            w.WriteStartElement("Mail");
            w.WriteElementString("Type", mailSettings.type);
            w.WriteElementString("Username", mailSettings.username);
            XmlPasswordWriter pw = new XmlPasswordWriter(w, passwordsEncrypted);
            pw.WritePasswordElementString("Password", mailSettings.password);
            /*if (passwordsEncrypted)
                w.WriteElementString("Password", GSN.CryptUtils.encrypt(mailSettings.password));
            else
                w.WriteElementString("Password", mailSettings.password);*/
            w.WriteElementString("Labels", mailSettings.labels);
            w.WriteElementString("Server", mailSettings.server);
            w.WriteElementString("Port", mailSettings.port.ToString());
            w.WriteEndElement(); // mail

            w.WriteElementString("SmsTemplate", smsTemplate);
            
            RulesConfigManager.saveRules(rules, w);

            w.WriteEndElement(); // settings
            w.WriteEndElement(); // gsn

            w.Close();

        }

    }
}
